import { _decorator, Component, Node, Vec3 } from 'cc';
import { FogGrid } from './FogGrid';
import { VisionSource } from './VisionSource';
import { VisionCache } from './VisionCache';

const { ccclass, property } = _decorator;

/**
 * 视野管理器
 * 
 * 功能：
 * 1. 管理所有视野源（如玩家、哨塔等）
 * 2. 处理视野的动态更新
 * 3. 实现基于射线的阴影计算
 * 4. 协调视野源和迷雾网格的交互
 * 
 * 优化：
 * 1. 间隔更新减少计算负担
 * 2. 支持多个视野源
 * 3. 可配置的阴影质量
 */
@ccclass('VisionManager')
export class VisionManager extends Component {
    @property(FogGrid)
    private fogGrid: FogGrid | null = null;

    @property([Node])
    private visionSources: Node[] = [];

    @property
    private updateInterval: number = 0.1;

    @property
    private checkObstacles: boolean = true;

    @property
    private shadowQuality: number = 8; // 阴影质量（射线检测数量）

    @property
    private useVisionCache: boolean = true;

    private updateTimer: number = 0;
    private visionCache: VisionCache = new VisionCache();
    private dirtyRegions: Set<string> = new Set();
    private updateQueue: Vec3[] = [];
    private isUpdating: boolean = false;

    update(dt: number) {
        this.updateTimer += dt;
        if (this.updateTimer >= this.updateInterval) {
            this.updateTimer = 0;
            this.updateVision();
        }

        if (this.updateQueue.length > 0) {
            this.updateVisionAsync();
        }

        // 处理脏区域
        if (this.dirtyRegions.size > 0) {
            this.updateDirtyRegions();
        }
    }

    private updateVision() {
        if (!this.fogGrid) return;

        for (const source of this.visionSources) {
            if (!source.active) continue;

            const visionComponent = source.getComponent(VisionSource);
            if (!visionComponent) continue;

            if (this.checkObstacles) {
                this.updateVisionWithShadows(source.position, visionComponent.visionRadius);
            } else {
                this.fogGrid.updateVisibility(source.position, visionComponent.visionRadius);
            }
        }
    }

    private updateVisionWithShadows(position: Vec3, radius: number) {
        // 计算阴影投射
        const angleStep = (Math.PI * 2) / this.shadowQuality;
        for (let angle = 0; angle < Math.PI * 2; angle += angleStep) {
            const endPoint = new Vec3(
                position.x + Math.cos(angle) * radius,
                position.y,
                position.z + Math.sin(angle) * radius
            );

            // 检查这条射线上的视线阻挡
            const visibility = this.fogGrid!.checkLineOfSight(position, endPoint);
            if (visibility > 0) {
                // 更新这条射线覆盖的区域
                this.updateVisibilityAlongRay(position, endPoint, radius, visibility);
            }
        }
    }

    private updateVisibilityAlongRay(start: Vec3, end: Vec3, radius: number, visibility: number) {
        const direction = new Vec3();
        Vec3.subtract(direction, end, start);
        const distance = direction.length();
        direction.normalize();

        const steps = Math.ceil(distance / this.fogGrid!.cellSize);
        const stepSize = distance / steps;

        for (let i = 0; i <= steps; i++) {
            const checkPoint = new Vec3(
                start.x + direction.x * stepSize * i,
                start.y,
                start.z + direction.z * stepSize * i
            );

            // 更新这个点的可见性
            this.fogGrid!.updateCellVisibility(checkPoint, visibility);
        }
    }

    public addVisionSource(source: Node) {
        if (!this.visionSources.includes(source)) {
            this.visionSources.push(source);
        }
    }

    public removeVisionSource(source: Node) {
        const index = this.visionSources.indexOf(source);
        if (index !== -1) {
            this.visionSources.splice(index, 1);
        }
    }

    public checkLineOfSight(from: Vec3, to: Vec3): number {
        // 将原来的私有方法改为公共方法
        return this.fogGrid!.checkLineOfSight(from, to);
    }

    public updateCellVisibility(position: Vec3, visibility: number): void {
        const gridSize = this.fogGrid!.getGridSize();
        const gridX = Math.floor((position.x + this.fogGrid!.mapSize.x / 2) / this.fogGrid!.cellSize);
        const gridY = Math.floor((position.z + this.fogGrid!.mapSize.z / 2) / this.fogGrid!.cellSize);

        if (gridX >= 0 && gridX < gridSize.x &&
            gridY >= 0 && gridY < gridSize.y) {
            this.fogGrid!.updateCellVisibility(position, visibility);
        }
    }

    private async updateVisionAsync() {
        if (this.isUpdating) return;
        this.isUpdating = true;

        while (this.updateQueue.length > 0) {
            const position = this.updateQueue.shift()!;
            await this.updateVisibilityForPosition(position);
            
            // 每处理一个位置后让出执行权
            await new Promise(resolve => setTimeout(resolve, 0));
        }

        this.isUpdating = false;
    }

    private async updateVisibilityForPosition(position: Vec3) {
        if (!this.fogGrid) return;

        // 获取视野范围内的所有格子
        const radius = this.getMaxVisionRadius();
        const cells = this.fogGrid.getCellsInRadius(position, radius);

        for (const cell of cells) {
            // 使用缓存检查视线
            if (this.useVisionCache) {
                const cached = this.visionCache.getCachedResult(position, cell);
                if (cached !== null) {
                    this.updateCellVisibility(cell, cached ? 1 : 0);
                    continue;
                }
            }

            // 计算新的视线结果
            const visibility = this.checkLineOfSight(position, cell);
            
            // 缓存结果
            if (this.useVisionCache) {
                this.visionCache.cacheResult(position, cell, visibility > 0);
            }

            this.updateCellVisibility(cell, visibility);
        }
    }

    private getMaxVisionRadius(): number {
        let maxRadius = 0;
        for (const source of this.visionSources) {
            const visionComponent = source.getComponent(VisionSource);
            if (visionComponent) {
                maxRadius = Math.max(maxRadius, visionComponent.visionRadius);
            }
        }
        return maxRadius;
    }

    private updateDirtyRegions() {
        const regionsToUpdate = Array.from(this.dirtyRegions);
        this.dirtyRegions.clear();

        for (const region of regionsToUpdate) {
            const [x, y] = region.split(',').map(Number);
            this.fogGrid?.updateRegion(x, y);
        }
    }
} 